
/**
 * This class is a part of Chat Voice Player View Library
 * Developed by: Jagar Yousef
 * Date: 2019
 */

package me.jagar.chatvoiceplayerlibrary;

import ohos.agp.colors.RgbColor;
import ohos.agp.components.AttrSet;
import ohos.agp.components.Component;
import ohos.agp.components.DirectionalLayout;
import ohos.agp.components.Image;
import ohos.agp.components.LayoutScatter;
import ohos.agp.components.ProgressBar;
import ohos.agp.components.Slider;
import ohos.agp.components.Text;
import ohos.agp.components.element.ShapeElement;
import ohos.agp.utils.Color;
import ohos.app.Context;
import ohos.media.audio.AudioManager;
import ohos.media.common.Source;
import ohos.media.player.Player;

public class VoicePlayerView extends DirectionalLayout {

    private Color playPaueseBackgroundColor, shareBackgroundColor, viewBackgroundColor,
            seekBarProgressColor, seekBarThumbColor, progressTimeColor, timingBackgroundColor,
            visualizationPlayedColor, visualizationNotPlayedColor, playProgressbarColor;
    private float viewCornerRadius, playPauseCornerRadius, shareCornerRadius;
    private boolean showShareButton = true, showTiming = true, enableVirtualizer = false;
    private ShapeElement playPauseShape, shareShape, viewShape;
    private Context context;
    private String shareTitle = "Share Voice";
    private byte[] bytes;
    private DirectionalLayout main_layout, padded_layout, container_layout;
    private Image imgPlay, imgPause, imgShare;
    private Slider seekBar;
    private Text txtProcess;
    private Player mediaPlayer;
    private ProgressBar pb_play;

    private PlayerVisualizerSeekbar seekbarv;

    public VoicePlayerView(Context context) {
        super(context);
        this.context = context;
    }

    public VoicePlayerView(Context context, AttrSet attrs) {
        super(context, attrs);
        initViews(context, attrs);
        this.context = context;
    }

    public VoicePlayerView(Context context, AttrSet attrs, String defStyleAttr) {
        super(context, attrs, defStyleAttr);
        initViews(context, attrs);
        this.context = context;
    }

    private void initViews(Context context, AttrSet attrs) {
        viewShape = new ShapeElement();
        playPauseShape = new ShapeElement();
        shareShape = new ShapeElement();
        if (attrs != null) {
            showShareButton = attrs.getAttr("showShareButton").get().getBoolValue();
            showTiming = attrs.getAttr("showTiming").get().getBoolValue();
            viewCornerRadius = attrs.getAttr("viewCornerRadius").get().getFloatValue();
            playPauseCornerRadius = attrs.getAttr("playPauseCornerRadius").get().getFloatValue();
            shareCornerRadius = attrs.getAttr("shareCornerRadius").get().getFloatValue();
            playPaueseBackgroundColor = attrs.getAttr("playPauseBackgroundColor").get().getColorValue();
            shareBackgroundColor = attrs.getAttr("shareBackgroundColor").get().getColorValue();
            viewBackgroundColor = attrs.getAttr("viewBackground").get().getColorValue();
            seekBarProgressColor = attrs.getAttr("seekBarProgressColor").get().getColorValue();
            seekBarThumbColor = attrs.getAttr("seekBarThumbColor").get().getColorValue();
            progressTimeColor = attrs.getAttr("progressTimeColor").get().getColorValue();
            shareTitle = attrs.getAttr("shareText").get().getStringValue();
            enableVirtualizer = attrs.getAttr("enableVirtualizer").get().getBoolValue();
            timingBackgroundColor = attrs.getAttr("timingBackgroundColor").get().getColorValue();
            visualizationNotPlayedColor = attrs.getAttr("visualizationNotPlayedColor").get().getColorValue();
            visualizationPlayedColor = attrs.getAttr("visualizationPlayedColor").get().getColorValue();
            playProgressbarColor = attrs.getAttr("playProgressbarColor").get().getColorValue();

            LayoutScatter.getInstance(context).parse(
                    ResourceTable.Layout_main_view, this, true);
            main_layout = (DirectionalLayout) findComponentById(ResourceTable.Id_collectorLinearLayout);
            padded_layout = (DirectionalLayout) findComponentById(ResourceTable.Id_paddedLinearLayout);
            container_layout = (DirectionalLayout) findComponentById(ResourceTable.Id_containerLinearLayout);
            imgPlay = (Image) findComponentById(ResourceTable.Id_imgPlay);
            imgPause = (Image) findComponentById(ResourceTable.Id_imgPause);
            imgShare = (Image) findComponentById(ResourceTable.Id_imgShare);
            seekBar = (Slider) findComponentById(ResourceTable.Id_seekBar2);
            txtProcess = (Text) findComponentById(ResourceTable.Id_txtTime);
            seekbarv = (PlayerVisualizerSeekbar) findComponentById(ResourceTable.Id_seekbarv);
            pb_play = (ProgressBar) findComponentById(ResourceTable.Id_pb_play);
            viewShape.setRgbColor(RgbColor.fromArgbInt(viewBackgroundColor.getValue()));
            viewShape.setCornerRadius(viewCornerRadius);
            playPauseShape.setRgbColor(RgbColor.fromArgbInt(playPaueseBackgroundColor.getValue()));
            playPauseShape.setCornerRadius(playPauseCornerRadius);
            shareShape.setRgbColor(RgbColor.fromArgbInt(shareBackgroundColor.getValue()));
            shareShape.setCornerRadius(shareCornerRadius);
            imgPlay.setBackground(playPauseShape);
            imgPause.setBackground(playPauseShape);
            imgShare.setBackground(shareShape);
            main_layout.setBackground(viewShape);
            seekBar.setProgressColor(seekBarProgressColor);
            ShapeElement thumbElement = new ShapeElement();
            thumbElement.setRgbColor(RgbColor.fromArgbInt(seekBarThumbColor.getValue()));
            thumbElement.setCornerRadius(100);
            seekBar.setThumbElement(thumbElement);
            ShapeElement element = new ShapeElement();
            element.setRgbColor(RgbColor.fromArgbInt(timingBackgroundColor.getValue()));
            element.setCornerRadius(25);
            txtProcess.setBackground(element);
            txtProcess.setPadding(16, 0, 16, 0);
            txtProcess.setTextColor(progressTimeColor);
            pb_play.setProgressColor(playProgressbarColor);
            if (!showShareButton) {
                imgShare.setVisibility(HIDE);
            }
            if (!showTiming) {
                txtProcess.setVisibility(INVISIBLE);
            }
            if (enableVirtualizer) {
                seekbarv.setVisibility(VISIBLE);
                seekBar.setVisibility(HIDE);
                ShapeElement shapeElement = new ShapeElement();
                shapeElement.setRgbColor(RgbColor.fromArgbInt(Color.TRANSPARENT.getValue()));
                seekbarv.setThumbElement(shapeElement);
                seekbarv.setProgressBackgroundElement(shapeElement);
                seekbarv.setProgressElement(shapeElement);
                seekbarv.setColors(visualizationPlayedColor, visualizationNotPlayedColor);
            }
        }
    }

    // Set the audio source and prepare mediaplayer
    public void setAudio(Source source, byte[] buffer) {
        byte[] clone = buffer.clone();
        bytes = clone;
        mediaPlayer = new Player(getContext());
        if (source != null) {
            try {
                mediaPlayer.setSource(source);
                mediaPlayer.setAudioStreamType(AudioManager.DEFAULT_VOLUME);
                mediaPlayer.setVolume(10);
                mediaPlayer.setPlayerCallback(new VideoPlayerCallback());
                mediaPlayer.prepare();
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
        seekBar.setValueChangedListener(seekBarListener);
        imgPlay.setClickedListener(imgPlayClickListener);
        imgPause.setClickedListener(imgPauseClickListener);
        imgShare.setClickedListener(imgShareClickListener);
        if (seekbarv.getVisibility() == VISIBLE) {
            seekbarv.updateVisualizer(buffer);
        }
        seekbarv.setValueChangedListener(seekBarListener);
        seekbarv.updateVisualizer(buffer);
    }

    private class VideoPlayerCallback implements Player.IPlayerCallback {

        @Override
        public void onPrepared() {
            seekBar.setMaxValue(mediaPlayer.getDuration() / 1000);
            if (seekbarv.getVisibility() == VISIBLE) {
                seekbarv.setMaxValue(mediaPlayer.getDuration() / 1000);
            }
            txtProcess.setText("00:00:00/" + convertSecondsToHMmSs(mediaPlayer.getDuration() / 1000));
        }

        @Override
        public void onMessage(int type, int extra) {

        }

        @Override
        public void onError(int errorType, int errorCode) {
            //在收到播放器错误消息时调用
        }

        @Override
        public void onResolutionChanged(int width, int height) {

        }

        @Override
        public void onPlayBackComplete() {
            context.getUITaskDispatcher().delayDispatch(new Runnable() {

                @Override
                public void run() {
                    imgPause.setVisibility(HIDE);
                    imgPlay.setVisibility(VISIBLE);
                }
            }, 200);
        }

        @Override
        public void onRewindToComplete() {

        }

        @Override
        public void onBufferingChange(int percent) {
            //在缓冲百分比更新时调用
        }

        @Override
        public void onNewTimedMetaData(Player.MediaTimedMetaData mediaTimedMetaData) {

        }

        @Override

        public void onMediaTimeIncontinuity(Player.MediaTimeInfo mediaTimeInfo) {

        }
    }

    ClickedListener imgPlayClickListener = new ClickedListener() {

        @Override
        public void onClick(Component component) {
            imgPause.setVisibility(VISIBLE);
            imgPlay.setVisibility(HIDE);
            mediaPlayer.play();
            try {
                update(mediaPlayer, txtProcess, seekBar, context);
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
    };

    private Slider.ValueChangedListener seekBarListener = new Slider.ValueChangedListener() {

        @Override
        public void onProgressUpdated(Slider slider, int progress, boolean fromUser) {
            if (fromUser) {
                long microseconds = progress * 1000 * 1000L;
                mediaPlayer.rewindTo(microseconds);
                update(mediaPlayer, txtProcess, seekBar, context);
                if (seekbarv.getVisibility() == VISIBLE) {
                    seekbarv.updatePlayerPercent((float) mediaPlayer.getCurrentTime() / mediaPlayer.getDuration());
                }
            }
        }

        @Override
        public void onTouchStart(Slider slider) {
            imgPause.setVisibility(HIDE);
            imgPlay.setVisibility(VISIBLE);
        }

        @Override
        public void onTouchEnd(Slider slider) {
            imgPlay.setVisibility(HIDE);
            imgPause.setVisibility(VISIBLE);
            if (!mediaPlayer.isNowPlaying()) {
                mediaPlayer.play();
            }
        }
    };

    ClickedListener imgPauseClickListener = new ClickedListener() {

        @Override
        public void onClick(Component component) {
            imgPause.setVisibility(HIDE);
            imgPlay.setVisibility(VISIBLE);
            mediaPlayer.pause();
        }
    };

    ClickedListener imgShareClickListener = new ClickedListener() {

        @Override
        public void onClick(Component view) {
            context.getUITaskDispatcher().asyncDispatch(new Runnable() {

                @Override
                public void run() {
                }
            });
        }
    };

    // Updating seekBar in realtime
    private void update(final Player mediaPlayer, final Text time, final Slider seekBar, final Context context) {
        context.getUITaskDispatcher().asyncDispatch(new Runnable() {

            @Override
            public void run() {
                seekBar.setProgressValue(mediaPlayer.getCurrentTime() / 1000);
                if (seekbarv.getVisibility() == VISIBLE) {
                    seekbarv.setProgressValue(mediaPlayer.getCurrentTime() / 1000);
                    seekbarv.updatePlayerPercent((float) mediaPlayer.getCurrentTime() / mediaPlayer.getDuration());
                }

                if (mediaPlayer.getDuration() / 1000 - mediaPlayer.getCurrentTime() / 1000 > 1) {
                    time.setText(convertSecondsToHMmSs(mediaPlayer.getCurrentTime() / 1000) + " / " + convertSecondsToHMmSs(mediaPlayer.getDuration() / 1000));
                } else {
                    time.setText(convertSecondsToHMmSs(mediaPlayer.getDuration() / 1000));
                    seekBar.setProgressValue(0);
                    if (seekbarv.getVisibility() == VISIBLE) {
                        seekbarv.updatePlayerPercent(0);
                        seekbarv.setProgressValue(0);
                    }
                }

                context.getUITaskDispatcher().delayDispatch(new Runnable() {

                    @Override
                    public void run() {
                        try {
                            if (mediaPlayer.getCurrentTime() > 0) {
                                try {
                                    update(mediaPlayer, time, seekBar, context);
                                } catch (Exception e) {
                                    e.printStackTrace();
                                }
                            }
                        } catch (Exception e) {
                            e.printStackTrace();
                        }
                    }
                }, 1000);
            }
        });
    }

    // Convert long milli seconds to a formatted String to display it
    private static String convertSecondsToHMmSs(long seconds) {
        long s = seconds % 60;
        long m = (seconds / 60) % 60;
        long h = (seconds / (60 * 60)) % 24;
        return String.format("%02d:%02d:%02d", h, m, s);
    }

    // These both functions to avoid mediaplayer errors
    public void onStop() {
        try {
            mediaPlayer.stop();
            mediaPlayer.reset();
            mediaPlayer.release();
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    public void onPause() {
        try {
            if (mediaPlayer != null) {
                if (mediaPlayer.isNowPlaying())
                    mediaPlayer.pause();
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
        imgPause.setVisibility(HIDE);
        imgPlay.setVisibility(VISIBLE);
    }

    // Programmatically functions
    public void setViewBackgroundShape(int color, float radius) {
        ShapeElement shape = new ShapeElement();
        shape.setRgbColor(RgbColor.fromArgbInt(color));
        shape.setCornerRadius(radius);
        main_layout.setBackground(shape);
    }

    public void setShareBackgroundShape(int color, float radius) {
        ShapeElement shape = new ShapeElement();
        shape.setRgbColor(RgbColor.fromArgbInt(color));
        shape.setCornerRadius(radius);
        imgShare.setBackground(shape);
    }

    public void setPlayPaueseBackgroundShape(int color, float radius) {
        ShapeElement shape = new ShapeElement();
        shape.setRgbColor(RgbColor.fromArgbInt(color));
        shape.setCornerRadius(radius);
        imgPause.setBackground(shape);
        imgPlay.setBackground(shape);
    }

    public void setSeekBarStyle(Color progressColor, Color thumbColor) {
        seekBar.setProgressColor(progressColor);
        seekBar.setScrollbarBackgroundColor(thumbColor);
    }

    public void setTimingVisibility(boolean visibility) {
        if (!visibility)
            txtProcess.setVisibility(INVISIBLE);
        else
            txtProcess.setVisibility(VISIBLE);
    }

    public void setShareButtonVisibility(boolean visibility) {
        if (!visibility)
            imgShare.setVisibility(HIDE);
        else
            imgShare.setVisibility(VISIBLE);
    }

    public void setShareText(String shareText) {
        shareTitle = shareText;
    }

    public void showPlayProgressbar() {
        imgPlay.setVisibility(HIDE);
        pb_play.setVisibility(VISIBLE);
    }

    public void hidePlayProgresbar() {
        pb_play.setVisibility(HIDE);
        imgPlay.setVisibility(VISIBLE);
    }

    public void refreshPlayer(Source source) {
        mediaPlayer = null;
        mediaPlayer = new Player(context);
        if (bytes != null) {
            try {
                mediaPlayer.setSource(source);
                mediaPlayer.setAudioStreamType(AudioManager.DEFAULT_VOLUME);
                mediaPlayer.setPlayerCallback(new VideoPlayerCallback());
                mediaPlayer.setVolume(10);
                mediaPlayer.prepare();
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
        seekBar.setValueChangedListener(seekBarListener);
        imgPlay.setClickedListener(imgPlayClickListener);
        imgPause.setClickedListener(imgPauseClickListener);
        imgShare.setClickedListener(imgShareClickListener);
        if (seekbarv.getVisibility() == VISIBLE) {
            seekbarv.updateVisualizer(bytes);
            seekbarv.setValueChangedListener(seekBarListener);
            seekbarv.updateVisualizer(bytes);
        }
    }

    public void refreshVisualizer() {
        if (seekbarv.getVisibility() == VISIBLE) {
            seekbarv.updateVisualizer(bytes);
        }
    }

    public ProgressBar getPlayProgressbar() {
        return pb_play;
    }

    public Color getPlayPaueseBackgroundColor() {
        return playPaueseBackgroundColor;
    }

    public void setPlayPaueseBackgroundColor(Color playPaueseBackgroundColor) {
        this.playPaueseBackgroundColor = playPaueseBackgroundColor;
    }

    public Color getShareBackgroundColor() {
        return shareBackgroundColor;
    }

    public void setShareBackgroundColor(Color shareBackgroundColor) {
        this.shareBackgroundColor = shareBackgroundColor;
    }

    public Color getViewBackgroundColor() {
        return viewBackgroundColor;
    }

    public void setViewBackgroundColor(Color viewBackgroundColor) {
        this.viewBackgroundColor = viewBackgroundColor;
    }

    public Color getSeekBarProgressColor() {
        return seekBarProgressColor;
    }

    public void setSeekBarProgressColor(Color seekBarProgressColor) {
        this.seekBarProgressColor = seekBarProgressColor;
    }

    public Color getSeekBarThumbColor() {
        return seekBarThumbColor;
    }

    public void setSeekBarThumbColor(Color seekBarThumbColor) {
        this.seekBarThumbColor = seekBarThumbColor;
    }

    public Color getProgressTimeColor() {
        return progressTimeColor;
    }

    public void setProgressTimeColor(Color progressTimeColor) {
        this.progressTimeColor = progressTimeColor;
    }

    public Color getTimingBackgroundColor() {
        return timingBackgroundColor;
    }

    public void setTimingBackgroundColor(Color timingBackgroundColor) {
        this.timingBackgroundColor = timingBackgroundColor;
    }

    public Color getVisualizationPlayedColor() {
        return visualizationPlayedColor;
    }

    public void setVisualizationPlayedColor(Color visualizationPlayedColor) {
        this.visualizationPlayedColor = visualizationPlayedColor;
    }

    public Color getVisualizationNotPlayedColor() {
        return visualizationNotPlayedColor;
    }

    public void setVisualizationNotPlayedColor(Color visualizationNotPlayedColor) {
        this.visualizationNotPlayedColor = visualizationNotPlayedColor;
    }

    public Color getPlayProgressbarColor() {
        return playProgressbarColor;
    }

    public void setPlayProgressbarColor(Color playProgressbarColor) {
        this.playProgressbarColor = playProgressbarColor;
    }

    public float getViewCornerRadius() {
        return viewCornerRadius;
    }

    public void setViewCornerRadius(float viewCornerRadius) {
        this.viewCornerRadius = viewCornerRadius;
    }

    public float getPlayPauseCornerRadius() {
        return playPauseCornerRadius;
    }

    public void setPlayPauseCornerRadius(float playPauseCornerRadius) {
        this.playPauseCornerRadius = playPauseCornerRadius;
    }

    public float getShareCornerRadius() {
        return shareCornerRadius;
    }

    public void setShareCornerRadius(float shareCornerRadius) {
        this.shareCornerRadius = shareCornerRadius;
    }

    public boolean isShowShareButton() {
        return showShareButton;
    }

    public void setShowShareButton(boolean showShareButton) {
        this.showShareButton = showShareButton;
    }

    public boolean isShowTiming() {
        return showTiming;
    }

    public void setShowTiming(boolean showTiming) {
        this.showTiming = showTiming;
    }

    public boolean isEnableVirtualizer() {
        return enableVirtualizer;
    }

    public void setEnableVirtualizer(boolean enableVirtualizer) {
        this.enableVirtualizer = enableVirtualizer;
    }

    public ShapeElement getPlayPauseShape() {
        return playPauseShape;
    }

    public void setPlayPauseShape(ShapeElement playPauseShape) {
        this.playPauseShape = playPauseShape;
    }

    public ShapeElement getShareShape() {
        return shareShape;
    }

    public void setShareShape(ShapeElement shareShape) {
        this.shareShape = shareShape;
    }

    public ShapeElement getViewShape() {
        return viewShape;
    }

    public void setViewShape(ShapeElement viewShape) {
        this.viewShape = viewShape;
    }

    public void setContext(Context context) {
        this.context = context;
    }

    public String getShareTitle() {
        return shareTitle;
    }

    public void setShareTitle(String shareTitle) {
        this.shareTitle = shareTitle;
    }

    public DirectionalLayout getMain_layout() {
        return main_layout;
    }

    public void setMain_layout(DirectionalLayout main_layout) {
        this.main_layout = main_layout;
    }

    public DirectionalLayout getPadded_layout() {
        return padded_layout;
    }

    public void setPadded_layout(DirectionalLayout padded_layout) {
        this.padded_layout = padded_layout;
    }

    public DirectionalLayout getContainer_layout() {
        return container_layout;
    }

    public void setContainer_layout(DirectionalLayout container_layout) {
        this.container_layout = container_layout;
    }

    public Image getImgPlay() {
        return imgPlay;
    }

    public void setImgPlay(Image imgPlay) {
        this.imgPlay = imgPlay;
    }

    public Image getImgPause() {
        return imgPause;
    }

    public void setImgPause(Image imgPause) {
        this.imgPause = imgPause;
    }

    public Image getImgShare() {
        return imgShare;
    }

    public void setImgShare(Image imgShare) {
        this.imgShare = imgShare;
    }

    public Slider getSeekBar() {
        return seekBar;
    }

    public void setSeekBar(Slider seekBar) {
        this.seekBar = seekBar;
    }

    public Text getTxtProcess() {
        return txtProcess;
    }

    public void setTxtProcess(Text txtProcess) {
        this.txtProcess = txtProcess;
    }

    public Player getMediaPlayer() {
        return mediaPlayer;
    }

    public void setMediaPlayer(Player mediaPlayer) {
        this.mediaPlayer = mediaPlayer;
    }

    public ProgressBar getPb_play() {
        return pb_play;
    }

    public void setPb_play(ProgressBar pb_play) {
        this.pb_play = pb_play;
    }

    public PlayerVisualizerSeekbar getseekbarv() {
        return seekbarv;
    }

    public void setseekbarv(PlayerVisualizerSeekbar seekbarv) {
        this.seekbarv = seekbarv;
    }

    public ClickedListener getImgPlayClickListener() {
        return imgPlayClickListener;
    }

    public void setImgPlayClickListener(ClickedListener imgPlayClickListener) {
        this.imgPlayClickListener = imgPlayClickListener;
    }

    public Slider.ValueChangedListener getSeekBarListener() {
        return seekBarListener;
    }

    public void setSeekBarListener(Slider.ValueChangedListener seekBarListener) {
        this.seekBarListener = seekBarListener;
    }

    public ClickedListener getImgPauseClickListener() {
        return imgPauseClickListener;
    }

    public void setImgPauseClickListener(ClickedListener imgPauseClickListener) {
        this.imgPauseClickListener = imgPauseClickListener;
    }

    public ClickedListener getImgShareClickListener() {
        return imgShareClickListener;
    }

    public void setImgShareClickListener(ClickedListener imgShareClickListener) {
        this.imgShareClickListener = imgShareClickListener;
    }
}
